﻿using System;
using System.Collections.Generic;
using System.Threading;
using agsXMPP.protocol.client;
using sharpxbot.Core.Threading;

namespace sharpxbot.Core.Messaging
{
    /// <summary>
    /// Represents abstract thread-safe implementation of IChannel interface.
    /// Override SendMessageImpl() method in concrete implementation
    /// </summary>
    public abstract class SharedChannel : IChannel, IActive
    {
        public const int DefaultChannelSleepTime = 100; //ms

        public SharedChannel()
        {
            messageQueue = new Queue<Message>();
            thread = new Thread(new ThreadStart(Run));
        }

        #region IChannel Members

        /// <summary>
        /// Performs asynchronous delevery of message
        /// </summary>
        /// <param name="msg"></param>
        public void Send(Message msg)
        {
            if (!IsRunning)
                throw new OperationCanceledException("Can't send message while channel is stopped. Start channel first");

            if (msg != null)
            {
                lock (messageQueue)
                {
                    try
                    {
                        messageQueue.Enqueue(msg);
                    }
                    catch { }
                }
            }
        }

        #endregion

        #region IActive Members

        public bool IsRunning { get; private set; }

        public void Start()
        {
            if (!IsRunning)
            {
                thread.Start();
                IsRunning = true;
            }
        }

        public void Stop()
        {
            if (IsRunning)
            {
                terminate = true;
            }
        }

        #endregion

        #region Protected methods

        protected abstract void SendMessageImpl(Message msg);

        #endregion

        #region Private methods

        private void Run()
        {
            while (!terminate)
            {
                Message msg = DequeueMessage();
                if (msg != null)
                {
                    SendMessageImpl(msg);
                }

                Thread.Sleep(DefaultChannelSleepTime);
            }

            IsRunning = false;
        }

        private Message DequeueMessage()
        {
            Message result = null;

            lock (messageQueue)
            {
                try
                {
                    if (messageQueue.Count > 0)
                    {
                        result = messageQueue.Dequeue();
                    }
                }
                catch { }
            }

            return result;
        }

        #endregion

        #region Private fields

        private Queue<Message> messageQueue;
        private Thread thread;
        private bool terminate;

        #endregion
    }
}
